<script setup lang="ts">
import { Delete, Edit, Plus } from '@element-plus/icons-vue'
import { onMounted, reactive, ref } from 'vue'
import {
  CascaderInstance,
  ElMessage,
  ElNotification,
  FormInstance,
  FormRules,
  TableInstance,
} from 'element-plus'
import {
  brandListRequest,
  addBrandRequest,
  updateBrandRequest,
  deleteBrandRequest,
  addCategoryBrandRelation,
  getCategoryBrandRelationRequest,
  deleteCategoryBrandRelationRequest,
} from '@/api/brand'
import { Brand, CategoryBrandRelation } from '@/api/brand/type'
import { useUserStore } from '@/stores/userStore'
import { getCredential } from '@/api/upload'
import type { Credential } from '@/api/upload/type'
import Oss from 'ali-oss'
import { queryAllCategories } from '@/api/category'
import type { CategoryVo } from '@/api/category/type'

// 表格弹性布局
const tableLayout = reactive<TableInstance['tableLayout']>('fixed')
// 品牌信息的数组
const items = ref<Brand[]>([])
// 总条数
const count = ref<number>(0)
// 当前页码
const currentPage = ref(1)
// 每页显示条数
const pageSize = ref(3)
// 分页查询方法
const pageNationQuery = async (pageNumber: number, pageSize: number, condition: string) => {
  if (condition === '') {
    condition = '%20'
  }
  await brandListRequest(pageNumber, pageSize, condition)
    .then((result) => {
      items.value = result.items
      count.value = result.count
    })
    .catch((err) => {
      console.log(err)
    })
}
// 刚进入品牌页面时发送请求，获取每一页的数据
onMounted(() => {
  pageNationQuery(1, 3, brandName.value)
})
// 改变当前页码的回调事件
const handleCurrentChange = (page: number) => {
  pageNationQuery(page, pageSize.value, brandName.value)
}
// 改变每页显示条数的回调事件
const handleSizeChange = () => {
  pageNationQuery(1, pageSize.value, brandName.value)
}
// 弹窗控制符
let dialogVisible = ref(false)
// 表单输入项
let brandVo = ref<Brand>({
  brandID: 0,
  name: '',
  logo: '',
  description: '',
  showStatus: null,
  firstLetter: '',
  sort: null,
})
// 点击添加按钮时的事件
const openAddBrandDialog = () => {
  dialogVisible.value = true
  ruleFormRef.value?.clearValidate()
}
// 文件上传成功时的钩子
const uploadSuccess = async (res: string) => {
  // await getCredential()
  //   .then(async (credential) => {
  //     const client = new Oss({
  //       bucket: 'mathmarket',
  //       region: 'oss-cn-beijing',
  //       accessKeyId: credential.accessKeyId,
  //       accessKeySecret: credential.accessKeySecret,
  //       stsToken: credential.securityToken,
  //     })
  //
  //     const file = rowFile
  //     const result = await client.put(file.name, file)
  //     console.log(result)
  //   })
  //   .catch((err: Error) => {
  //     console.log(err)
  //   })
  // 校验图片大小和格式
  brandVo.value.logo = res
}
// 文件上传前的钩子
const beforeBrandImgUpload = (rawFile: File) => {
  if (
    rawFile.type.toString() !== 'image/jpeg' &&
    rawFile.type.toString() !== 'image/jpg' &&
    rawFile.type.toString() !== 'image/gif' &&
    rawFile.type.toString() !== 'image/png'
  ) {
    ElNotification({
      title: '图片格式不正确，只能为 jpg,png,jpeg,gif中的一种',
    })
    return false
  }
  if (rawFile.size / 1024 / 1024 > 4) {
    ElNotification({
      title: '图片大小不能超过4M',
    })
    return false
  }
  return true
}
const ruleFormRef = ref<FormInstance>()
// 校验品牌名称
const validateName = (rule: any, value: any, callback: any) => {
  if (value === '') {
    callback(new Error('品牌名称不能为空'))
  } else if (value > 20 || brandVo.value.name.length < 2) {
    callback(new Error('品牌名称长度在2到20之间'))
  }
  callback()
}
// 校验logo
const validateLogo = (rule: any, value: any, callback: any) => {
  if (value === '') {
    callback(new Error('品牌LOGO不能为空'))
  }
  callback()
}
// 校验显示状态
const validateShowStatus = (rule: any, value: any, callback: any) => {
  if (value === null) {
    callback(new Error('请选择显示状态'))
  }
  callback()
}
// 校验描述信息
const validateDescription = (rule: any, value: any, callback: any) => {
  if (value === '') {
    callback(new Error('品牌描述信息不能为空'))
  } else if (value.length > 1000) {
    callback(new Error('品牌描述不能超过1000个字符'))
  }
  callback()
}
// 校验检索首字母
const validateFirstLetter = (rule: any, value: any, callback: any) => {
  if (value === '') {
    callback(new Error('检索首字母不能为空'))
  } else if (value.length > 1) {
    callback(new Error('只能输入一个字符'))
  }
  callback()
}
// 校验排序
const validateSort = (rule: any, value: any, callback: any) => {
  if (Number(value) > 0) {
    callback()
  }
  callback(new Error('请输入一个正整数'))
}
// 表单校验规则
const rules = reactive<FormRules<typeof brandVo>>({
  name: [{ validator: validateName, trigger: 'blur' }],
  logo: [{ validator: validateLogo, trigger: 'blur' }],
  description: [{ validator: validateDescription, trigger: 'blur' }],
  showStatus: [{ validator: validateShowStatus, trigger: 'blur' }],
  firstLetter: [{ validator: validateFirstLetter, trigger: 'blur' }],
  sort: [{ validator: validateSort, trigger: 'blur' }],
})
// 点击修改按钮的事件
const updateBrand = (row: Brand) => {
  dialogVisible.value = true
  ruleFormRef.value?.clearValidate()
  Object.assign(brandVo.value, row)
}
// 表单确定按钮单击事件
const onSubmit = async () => {
  // 若id为0则新增品牌
  if (brandVo.value.brandID === 0) {
    await ruleFormRef
      // 表单校验
      .value!.validate(async (res) => {
        if (res) {
          // 发送保存品牌的请求
          await addBrandRequest(brandVo.value)
            .then((res) => {
              // 保存成功之后关闭弹窗
              dialogVisible.value = false
              // 清空表单数据
              clearForm()
              currentPage.value = 1
              // 重新查询
              pageNationQuery(currentPage.value, pageSize.value, brandName.value)
              ElMessage({
                message: '保存成功',
                type: 'success',
              })
            })
            .catch((err: Error) => {
              console.log(err)
            })
        }
      })
      .catch((err: Error) => {
        console.log(err)
      })
  } else {
    // 若id不0为0则更新品牌
    await ruleFormRef
      // 表单校验
      .value!.validate(async (res) => {
        if (res) {
          // 发送修改品牌的请求
          await updateBrandRequest(brandVo.value)
            // 修改成功之后关闭弹窗
            .then((res) => {
              dialogVisible.value = false
              clearForm()
              pageNationQuery(currentPage.value, pageSize.value, brandName.value)
              ElMessage({
                message: '修改成功.',
                type: 'success',
              })
            })
            .catch((err: Error) => {
              console.log(err)
            })
        }
      })
      .catch((err: Error) => {
        console.log(err)
      })
  }
}
// 删除品牌按钮单击事件
const confirmEvent = async (brandVo: Brand) => {
  await deleteBrandRequest([brandVo.brandID])
    .then((res) => {
      ElMessage({
        message: '删除成功',
        type: 'success',
      })
      // 重新查询
      pageNationQuery(currentPage.value, pageSize.value, brandName.value)
    })
    .catch((err: Error) => {
      console.log(err)
    })
}
// 多选
const selectable = () => true

// 清空表单数据
const clearForm = () => {
  brandVo.value.brandID = 0
  brandVo.value.name = ''
  brandVo.value.logo = ''
  brandVo.value.description = ''
  brandVo.value.showStatus = null
  brandVo.value.firstLetter = ''
  brandVo.value.sort = null
}
// 引入用户仓库
const userStore = useUserStore()
const buttons = userStore.buttons
// 品牌名称
const brandName = ref<string>('')
// 查询按钮单击事件
const queryBrands = async () => {
  await pageNationQuery(currentPage.value, pageSize.value, brandName.value)
}
// 表格实例对象
const brandTable = ref<TableInstance>()
// 批量删确定按钮回调事件
const batchDelete = async () => {
  let brandIds: number[] = []
  brandTable.value?.getSelectionRows().forEach((row) => {
    brandIds.push(row.brandID)
  })
  await deleteBrandRequest(brandIds).then((res) => {
    pageNationQuery(currentPage.value, pageSize.value, brandName.value)
    brandIds = []
  })
}
// 控制关联分类对话框显示与隐藏.true-弹出，false-隐藏
const relationShipDialogVisible = ref(false)
// 分类信息集合
const categoryVos = ref<CategoryVo[]>()
let categoryBrandRelation: CategoryBrandRelation = {
  categoryBrandRelationID: 0,
  brandID: 0,
  categoryID: 0,
  brandName: '',
  categoryName: '',
}
// 关联分类按钮回调事件
const addCategoryToBrand = (row: Brand) => {
  categoryBrandRelation.brandID = row.brandID
  categoryBrandRelation.brandName = row.name
  relationShipDialogVisible.value = true
  // 查询分类信息
  queryAllCategories()
    .then((res) => {
      categoryVos.value = res
      return getCategoryBrandRelationRequest(categoryBrandRelation.brandID)
    })
    .then((res) => {
      categoryBrandRelations.value = res
    })
}
// 控制级联选择器的显示与隐藏;true-弹出，false-隐藏
const cascaderVisible = ref(false)
// 新增关联按钮回调事件
const newRelationShip = () => {
  categoryID.value = 0
  cascaderVisible.value = true
}
const cacasderProps = { label: 'name', value: 'categoryID', children: 'children' }
// 分类id
const categoryID = ref<number[]>()
// 级联选择器的实例对象
const cascaderRef = ref<CascaderInstance>()
const categoryBrandRelations = ref<CategoryBrandRelation[]>()
// 新增关联确定按钮回调事件
const newRelationShipConfirm = async () => {
  categoryBrandRelation.categoryID = cascaderRef.value.getCheckedNodes(false)[0].data
    ?.categoryID as number
  categoryBrandRelation.categoryName = cascaderRef.value.getCheckedNodes(false)[0].data
    ?.name as string
  await addCategoryBrandRelation(categoryBrandRelation).then((res) => {
    cascaderVisible.value = false
    getCategoryBrandRelationRequest(categoryBrandRelation.brandID).then((res) => {
      categoryBrandRelations.value = res
    })
  })
}
// 删除品牌与分类的关联
const deleteRelation = async (row) => {
  await deleteCategoryBrandRelationRequest(row.categoryBrandRelationID).then((res) => {
    getCategoryBrandRelationRequest(categoryBrandRelation.brandID).then((res) => {
      categoryBrandRelations.value = res
    })
  })
}
</script>
`
<template>
  <div style="padding-left: 0.5rem">
    <el-input
      placeholder="品牌名称"
      style="width: 15rem"
      v-model="brandName"
      v-if="buttons?.includes('QueryBrand')"
    ></el-input>
    <el-button @click="queryBrands" v-if="buttons?.includes('QueryBrand')">查询</el-button>
    <!--    添加品牌按钮-->
    <el-button
      class="el-button"
      type="primary"
      :icon="Plus"
      @click="openAddBrandDialog"
      v-if="buttons?.includes('AddBrand')"
    >
      添加品牌
    </el-button>
    <el-popconfirm title="确定要删除吗?" @confirm="batchDelete">
      <template #reference>
        <el-button type="danger" v-if="buttons?.includes('DeleteBrand')">批量删除</el-button>
      </template>
    </el-popconfirm>
  </div>
  <!--    添加及修改品牌弹窗-->
  <el-dialog
    class="el-dialog"
    v-model="dialogVisible"
    :title="brandVo.brandID === 0 ? '新增品牌' : '修改品牌'"
    width="800"
    draggable
    overflow
  >
    <el-form
      class="el-form"
      label-position="right"
      label-width="6.25rem"
      ref="ruleFormRef"
      :rules="rules"
      :model="brandVo"
    >
      <el-form-item label="品牌名" prop="name">
        <el-input v-model="brandVo.name" />
      </el-form-item>
      <el-form-item label="介绍" prop="description">
        <el-input v-model="brandVo.description" />
      </el-form-item>
      <el-form-item label="显示状态" prop="showStatus">
        <el-radio-group v-model="brandVo.showStatus">
          <el-radio :value="true">显示</el-radio>
          <el-radio :value="false">不显示</el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="检索首字母" prop="firstLetter">
        <el-input v-model="brandVo.firstLetter" />
      </el-form-item>
      <el-form-item label="排序" prop="sort">
        <el-input v-model="brandVo.sort" />
      </el-form-item>
      <el-form-item label="品牌LOGO" prop="logo">
        <el-upload
          class="avatar-uploader"
          action="/dev-api/File/OnPostUpload"
          :show-file-list="false"
          :on-success="uploadSuccess"
          :before-upload="beforeBrandImgUpload"
        >
          <img v-if="brandVo.logo" :src="brandVo.logo" class="avatar" alt="" />
          <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
        </el-upload>
      </el-form-item>
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="onSubmit">确定</el-button>
      </div>
    </template>
  </el-dialog>
  <!--    表格-->
  <el-scrollbar class="el-scrollbar">
    <div class="main-content">
      <el-table
        :data="items"
        border
        style="width: 100%"
        :table-layout="tableLayout"
        ref="brandTable"
      >
        <el-table-column
          type="selection"
          :selectable="selectable"
          align="center"
          width="81"
        ></el-table-column>
        <el-table-column type="index" align="center" />
        <el-table-column prop="name" align="center" label="品牌名称" />
        <el-table-column align="center" label="品牌LOGO">
          <template #default="scope">
            <el-image :src="scope.row.logo"></el-image>
          </template>
        </el-table-column>
        <el-table-column align="center" label="显示状态">
          <template #default="scope">
            <el-switch v-model="scope.row.showStatus" disabled />
          </template>
        </el-table-column>
        <el-table-column prop="firstLetter" align="center" label="检索首字母" />
        <el-table-column prop="sort" align="center" label="排序" />
        <el-table-column align="center" label="操作">
          <template #default="scope">
            <el-button
              type="success"
              @click="addCategoryToBrand(scope.row)"
              v-if="buttons?.includes('EditBrand')"
            >
              关联分类
            </el-button>
            <el-button
              type="primary"
              :icon="Edit"
              size="small"
              @click="updateBrand(scope.row)"
              v-if="buttons?.includes('EditBrand')"
            />
            <el-popconfirm
              confirm-button-text="确定"
              cancel-button-text="取消"
              icon-color="#626AEF"
              title="确定要删除吗?"
              @confirm="confirmEvent(scope.row)"
            >
              <template #reference>
                <el-button
                  type="danger"
                  size="small"
                  :icon="Delete"
                  v-if="buttons?.includes('DeleteBrand')"
                />
              </template>
            </el-popconfirm>
          </template>
        </el-table-column>
      </el-table>
    </div>
  </el-scrollbar>
  <!--  关联分类对话框-->
  <el-dialog title="关联分类" v-model="relationShipDialogVisible" style="width: 40rem">
    <el-button style="margin-left: 0" @click="newRelationShip">新增关联</el-button>
    <el-table :data="categoryBrandRelations">
      <el-table-column label="序号" type="index" align="center" width="100"></el-table-column>
      <el-table-column label="品牌名称" prop="brandName" align="center"></el-table-column>
      <el-table-column label="分类" prop="categoryName" align="center"></el-table-column>
      <el-table-column label="操作" align="center">
        <template #default="scope">
          <el-button @click="deleteRelation(scope.row)" type="danger">移除</el-button>
        </template>
      </el-table-column>
    </el-table>
  </el-dialog>
  <!--  关联分类级联选择器-->
  <el-dialog v-model="cascaderVisible" style="width: 15rem">
    <el-cascader
      :options="categoryVos"
      :props="cacasderProps"
      v-model="categoryID"
      ref="cascaderRef"
    ></el-cascader>
    <template #footer>
      <div class="cascader-footer">
        <el-button @click="cascaderVisible = false">取消</el-button>
        <el-button type="primary" @click="newRelationShipConfirm">确认</el-button>
      </div>
    </template>
  </el-dialog>
  <!--    分页器-->
  <el-pagination
    style="margin-left: 0.5rem"
    v-model:current-page="currentPage"
    class="el-pagination"
    background
    layout="prev, pager, next, sizes"
    :total="count"
    :page-sizes="[3, 10, 20, 40]"
    v-model:page-size="pageSize"
    @size-change="handleSizeChange"
    @current-change="handleCurrentChange"
  />
</template>

<style scoped>
.el-button {
  margin-left: 1.25rem;
}

.el-dialog {
  .el-form {
    padding: 2rem;
  }
}
.el-scrollbar {
  height: calc(100vh - 10rem);

  .main-content {
    margin: 0.5rem;
    border: 2px solid #e4e4e4;
    padding: 1rem;

    .avatar-uploader .el-upload {
      border: 1px dashed var(--el-border-color);
      border-radius: 6px;
      cursor: pointer;
      position: relative;
      overflow: hidden;
      transition: var(--el-transition-duration-fast);
    }
  }
}

.avatar-uploader .avatar {
  width: 11rem;
  height: 11rem;
  display: block;
}

.el-pagination {
  padding: 1rem 0;
}
</style>

<style>
.avatar-uploader .el-upload {
  border: 1px solid #dcdfe6;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}

.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 12rem;
  height: 12rem;
  text-align: center;
}
</style>
